package com.eight.cloud.job.service.impl;

import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.eight.cloud.job.common.constants.ScheduleConstants;
import com.eight.cloud.job.entity.ExecutionJobEntity;
import com.eight.cloud.job.mapper.ExecutionJobMapper;
import com.eight.cloud.job.model.dto.ExecutionJobDto;
import com.eight.cloud.job.model.dto.ExecutionJobQueryDto;
import com.eight.cloud.job.model.vo.JobDataMapVo;
import com.eight.cloud.job.service.IExecutionJobService;
import com.eight.cloud.job.util.ScheduleUtils;
import com.eight.cloud.mybatisplus.service.BaseService;
import org.quartz.JobDataMap;
import org.quartz.JobKey;
import org.quartz.Scheduler;
import org.quartz.SchedulerException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import javax.annotation.Resource;
import java.util.List;

/**
 * @ClassName: ExecutionJobServiceImpl
 * @Author: TXC
 * @Date: 2025-02-25 10:12
 **/
@Service
public class ExecutionJobServiceImpl extends BaseService<ExecutionJobMapper, ExecutionJobEntity> implements IExecutionJobService {
    @Resource
    private Scheduler scheduler;

    /**
     * 项目启动时，初始化定时器 主要是防止手动修改数据库导致未同步到定时任务处理（注：不能手动修改数据库ID和任务组名，否则会导致脏数据）
     */
    @Override
    public void initExecutionJob() throws SchedulerException {
        scheduler.clear();
        List<JobDataMapVo> jobDataMapList = baseMapper.fetchAllJobDataMap();
        for (JobDataMapVo jobDataMap : jobDataMapList) {
            ScheduleUtils.createScheduleJob(scheduler, jobDataMap);
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addCronJob(ExecutionJobDto executionJob) throws SchedulerException {
        ExecutionJobEntity executionJobEntity = convertToEntity(executionJob);
        int rows = baseMapper.insert(executionJobEntity);
        if (rows > 0) {
            JobDataMapVo jobDataMap = fetchJobDataMap(executionJobEntity.getUuid());
            ScheduleUtils.createScheduleJob(scheduler, jobDataMap);
        }
    }

    @Override
    public void updateCronJob(ExecutionJobDto executionJob) throws SchedulerException {
        ExecutionJobEntity executionJobEntity = convertToEntity(executionJob);
        int rows = baseMapper.updateById(executionJobEntity);
        if (rows > 0) {
            JobDataMapVo jobDataMap = fetchJobDataMap(executionJobEntity.getUuid());
            JobKey jobKey = ScheduleUtils.getJobKey(jobDataMap);
            if (scheduler.checkExists(jobKey)) {
                scheduler.deleteJob(ScheduleUtils.getJobKey(jobDataMap));
            }
            ScheduleUtils.createScheduleJob(scheduler, jobDataMap);
        }
    }

    @Override
    public void execute(String uuid) throws SchedulerException {
        JobDataMapVo jobDataMap = fetchJobDataMap(uuid);
        // 参数
        JobDataMap dataMap = new JobDataMap();
        dataMap.put(ScheduleConstants.TASK_PROPERTIES, jobDataMap);
        scheduler.triggerJob(ScheduleUtils.getJobKey(jobDataMap), dataMap);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void pauseJob(String uuid) throws SchedulerException {
        ExecutionJobEntity executionJobEntity = getByUuid(uuid);
        executionJobEntity.setStatus(ScheduleConstants.ExecutionJobStatus.PAUSE.getValue());
        int rows = baseMapper.updateById(executionJobEntity);
        if (rows > 0) {
            JobDataMapVo jobDataMap = fetchJobDataMap(uuid);
            scheduler.pauseJob(ScheduleUtils.getJobKey(jobDataMap));
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void resumeJob(String uuid) throws SchedulerException {
        ExecutionJobEntity executionJobEntity = getByUuid(uuid);
        executionJobEntity.setStatus(ScheduleConstants.ExecutionJobStatus.NORMAL.getValue());
        int rows = baseMapper.updateById(executionJobEntity);
        if (rows > 0) {
            JobDataMapVo jobDataMap = fetchJobDataMap(uuid);
            scheduler.resumeJob(ScheduleUtils.getJobKey(jobDataMap));
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteJob(String uuid) throws SchedulerException {
        JobDataMapVo jobDataMap = fetchJobDataMap(uuid);
        int rows = baseMapper.realDelete(lambdaQueryWrapper().eq(ExecutionJobEntity::getUuid, uuid));
        if (rows > 0) {
            JobKey jobKey = ScheduleUtils.getJobKey(jobDataMap);
            if (scheduler.checkExists(jobKey)) {
                scheduler.deleteJob(ScheduleUtils.getJobKey(jobDataMap));
            }
        }
    }

    @Override
    public JobDataMapVo fetchJobDataMap(String uuid) {
        return baseMapper.fetchJobDataMap(uuid);
    }

    @Override
    public void fetchPageJobDataMap(IPage<JobDataMapVo> page, ExecutionJobQueryDto queryDto) {
        baseMapper.fetchPageJobDataMap(page, queryDto);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteJob(List<String> jobIds) {
        if (ObjectUtil.isNotEmpty(jobIds)) {
            List<ExecutionJobEntity> executionJobs = baseMapper.selectList(lambdaQueryWrapper()
                    .in(ExecutionJobEntity::getQuartzJobId, jobIds));
            executionJobs.forEach(executionJob -> {
                try {
                    deleteJob(executionJob.getUuid());
                } catch (SchedulerException e) {
                    throw new RuntimeException(e);
                }
            });
        }
    }
}
